rm(list = ls())
# library("rstudioapi")
# setwd(dirname(getActiveDocumentContext()$path))

Uncomment and run this block if you haven’t had these packages installed

# install.packages("ona", repos = c("https://cran.qe-libs.org", "https://cran.rstudio.org"))
# install.packages("tma", repos = c("https://cran.qe-libs.org", "https://cran.rstudio.org"))
# install.packages("magrittr")

0. setting up constant variables (change as appropriate)

# mapid = "23230129"
mapid = "21078015"
# mapid = "24096504"
wd = paste0(getwd(), "/data/")

0. read A B C matrices and other relevant data

A_matrix = read_csv(paste0(wd, mapid, "_a_matrix.csv"))
B_matrix = read_csv(paste0(wd, mapid, "_b_matrix.csv"))
C_matrix = read.csv(paste0(wd, mapid, "_c_matrix.csv"))
sh_info = read.csv(paste0(wd, "LEM text - Stakeholders.csv"))
A = jsonlite::read_json(paste0(wd, mapid, "_init_map.json"))
reps = jsonlite::read_json(paste0(wd, mapid, "_reps.json"))
sub_result = readRDS(paste0(wd, mapid, "a_sub_result_new.rds")) #record satisfy level
sh_name = A_matrix %>%
  select(c(Name)) %>%
  unique() %>%
  pull()
sh_info = sh_info %>% 
  filter(Name %in% sh_name) %>% 
  arrange(match(Name, sh_name)) %>% 
  unite("SHinfo", Name:Direction, remove = TRUE) %>% 
  pull()
name_col = sh_name
ind_col = c()
dir_col = c()
group_col = c()
for (i in 1:length(A$indicators)) {
  for (j in 1:length(A$indicators[[i]]$stakeholders)) {
    ind_col <- append(ind_col, A$indicators[[i]]$stakeholders[[j]]$indKey)
    dir_col <- append(dir_col, A$indicators[[i]]$stakeholders[[j]]$direction)
    group_col <- append(group_col, A$indicators[[i]]$stakeholders[[j]]$stakeholderGroup)
  }
}
sh_df <- data.frame(name = name_col, indicator = ind_col, direction = dir_col, group = group_col)
sh_df
business <- sh_df %>% filter(group == "Local Business Consortium")
business <- business$name
environmental <- sh_df %>% filter(group == "Environmental Justice Center")
environmental <- environmental$name
community <- sh_df %>% filter(group == "Community Coalition")
community <- community$name
submission_name = C_matrix$user_name
submission_order = c()
sub_approval_count = c()
sub_order_num= c()


for (i in 1:length(sub_result)){
  submission_order = append(submission_order, sub_result[[i]]$userKey)
  sub_order_num = append(sub_order_num, sub_result[[i]]$submissionCount)
  sub_approval_count = append(sub_approval_count, sub_result[[i]]$approvalCount)
}
submission_df <- data.frame(userKey = submission_order, submissionCount = sub_order_num, approvalCount = sub_approval_count)
uniqueUsers <- unique(submission_df$userKey)
print(submission_df)
print(uniqueUsers)
  [1] "jsignorella"                                     "Tony_lacen"                                     
  [3] "Autumn"                                          "Angelina123"                                    
  [5] "mohamed711"                                      "SofiaTorres"                                    
  [7] "diego"                                           "JacksonK"                                       
  [9] "TekoaMyers"                                      "giannasx3"                                      
 [11] "Isabella"                                        "amyaharidano13"                                 
 [13] "ShiMyers"                                        "AnthonyD"                                       
 [15] "kasinrose1"                                      "Ariana_25"                                      
 [17] "Cole"                                            "KylieF"                                         
 [19] "Deandre"                                         "Jada"                                           
 [21] "ChaseB."                                         "audrie.ambeault"                                
 [23] "Eric"                                            "jodilamagna"                                    
 [25] "[\\p{L}\\p{M}\\p{S}\\p{N}\\p{P}]+"               "nicholaschaber"                                 
 [27] "Jenniferfall"                                    "AubreyH"                                        
 [29] "nick"                                            "Nathen"                                         
 [31] "robloxman225"                                    "Kabaiaa"                                        
 [33] "hhaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "Amanda"                                         
 [35] "BryceG13"                                        "Jayna"                                          
 [37] "HectorMajor"                                     "NicholasP"                                      
 [39] "Teyshann11"                                      "Meghanmelo"                                     
 [41] "AidenD"                                          "cole13"                                         
 [43] "DylanJodoin123"                                  "Colin_Danko_25"                                 
 [45] "Elijah25"                                        "emmguerra"                                      
 [47] "Caden"                                           "VictoriaB"                                      
 [49] "Synthia"                                         "TannerD"                                        
 [51] "Cstpierre"                                       "LoganM22"                                       
 [53] "Caitlin"                                         "Neves7C"                                        
 [55] "HannahSorel"                                     "HunterK"                                        
 [57] "Aiden"                                           "AydenH"                                         
 [59] "addisonboulris_"                                 "gracie"                                         
 [61] "PaytonG14"                                       "mainmandiaw3545"                                
 [63] "Esaraiva"                                        "Hailey"                                         
 [65] "Marcos"                                          "EthanTaylor25"                                  
 [67] "GabeS"                                           "Sofia214Torres"                                 
 [69] "Tiffany"                                         "MarquellMoniz25"                                
 [71] "RyanG"                                           "Daniel"                                         
 [73] "Alexa"                                           "addisonboulris"                                 
 [75] "Linnea"                                          "Hunter"                                         
 [77] "Collin"                                          "Grace"                                          
 [79] "anto.nella"                                      "AaronFerreira"                                  
 [81] "Leyla"                                           "Alysiah"                                        
 [83] "HaileyP"                                         "Zackary"                                        
 [85] "Lila"                                            "TimmyTomlinson25"                               
 [87] "EricaP"                                          "ConnorHogan"                                    
 [89] "butterfly"                                       "DavidGa"                                        
 [91] "graciel"                                         "Mayolifs"                                       
 [93] "rboler25"                                        "nchaber123"                                     
 [95] "Shawn"                                           "Marlenyg"                                       
 [97] "AlexiaB"                                         "AidanPereira"                                   
 [99] "Bigboi1234"                                      "Monicaking"                                     
[101] "Kabaia"                                          "joziah12"                                       
[103] "D4v0nt43"                                        "EdgarP"                                         
[105] "Noleen"                                          "MissFrizzle"                                    
[107] "Soph.martini"                                    "EdgarP190"                                      
[109] "SophiaP"                                         "amyah131"                                       
[111] "NathanG"                                         "Marcus25"                                       
[113] "JaredL"                                          "Emmanewberg"                                    
[115] "alexn"                                           "Oscar"                                          
[117] "JettB"                                           "jazlynf"                                        
[119] "jacobw"                                          "NolanKelly25"                                   
[121] "Nicoleoliveira"                                  "JeremyS"                                        
[123] "AndrewG"                                         "DonutD4V0NT43"                                  
[125] "Taylorg1209"                                     "TekoaM"                                         
[127] "AidenDawley"                                     "rachaelbonner25"                                
[129] "Makaylah23"                                      "Travis"                                         
[131] "Jordan"                                          "jellyboyjazzy"                                  
[133] "Aswafford25"                                     "Ryan"                                           
[135] "joditeach"                                      

Filter only users with more than 2 submissions

uniqueUsers_filtered <- submission_df %>%
  group_by(userKey) %>% 
  summarise(Count = n()) %>%
  filter(Count > 2)

uniqueUsers_filtered <- uniqueUsers_filtered$userKey
numPlots <- 7 # adjust as appropriate
batchSize <- ceiling(length(uniqueUsers_filtered) / numPlots)

for (i in 1:numPlots) {
  batch <- submission_df %>% filter(userKey %in% uniqueUsers_filtered[(((i-1) * batchSize) + 1):(min(length(uniqueUsers_filtered), i * batchSize))])
  
  # Create a line plot using ggplot2
  p <- ggplot(batch, aes(x = submissionCount, y = approvalCount, color = userKey, linetype = userKey)) +
    geom_line(size=1) +
    scale_x_continuous(breaks = 1:nrow(submission_df), labels = 1:nrow(submission_df), minor_breaks = NULL) +
    scale_y_continuous(breaks = seq(0, max(submission_df$approvalCount), by = 1), minor_breaks = NULL) +
    theme_minimal()
  print(p)
}

Prepare dataframe for stacked barplot

submission_detailed_df <- data.frame(userKey = character(), submissionCount = integer(), business = integer(),
                                     businessMax = integer(), environmental = integer(), environmentalMax = integer(),
                                     community = integer(), communityMax = integer())
for (i in 1:length(sub_result)) {
  if (sub_result[[i]]$userKey %in% uniqueUsers_filtered) {
    b_max = sum(business %in% sub_result[[i]]$stakeholders)
    e_max = sum(environmental %in% sub_result[[i]]$stakeholders)
    c_max = sum(community %in% sub_result[[i]]$stakeholders)
    b_select = sub_result[[i]]$stakeholders[sub_result[[i]]$stakeholders %in% business]
    e_select = sub_result[[i]]$stakeholders[sub_result[[i]]$stakeholders %in% environmental]
    c_select = sub_result[[i]]$stakeholders[sub_result[[i]]$stakeholders %in% community]
    b_count = 0
    e_count = 0
    c_count = 0
    for (b in b_select) {
      b_count = b_count + sub_result[[i]]$stakeholderApproval[[b]]
    }
    for (e in e_select) {
      e_count = e_count + sub_result[[i]]$stakeholderApproval[[e]]
    }
    for (c in c_select) {
      c_count = c_count + sub_result[[i]]$stakeholderApproval[[c]]
    }
    submission_detailed_df <- rbind(submission_detailed_df, data.frame(userKey = sub_result[[i]]$userKey,
                                    submissionCount = sub_result[[i]]$submissionCount, business = b_count,
                                    businessMax = b_max, environmental = e_count, environmentalMax = e_max,
                                    community = c_count, communityMax = c_max))
  }
}
bar_width = 0.5
dodge_width <- 0  # Adjust this as needed
expand_mults <- c(0, 0.5)
submissionCount_levels <- as.character(unique(submission_detailed_df$submissionCount))
for (user in uniqueUsers_filtered) {
  b_plot <- ggplot(submission_detailed_df %>% filter(userKey == user), aes(x = factor(submissionCount))) +
    geom_bar(aes(y = businessMax), stat = "identity", fill = "gainsboro", position = position_dodge(width = dodge_width), width = bar_width) +
    geom_bar(aes(y = business), stat = "identity", fill = "cornflowerblue", position = position_dodge(width = dodge_width), width = bar_width) +
    labs(title = "Business",
         x = "submissionCount",
         y = "count",
         fill = "Variable") +
    theme_minimal()
  # +
  #   scale_x_discrete(expand = expand_scale(mult = expand_mults, add = c(0, 0)))
  # Assuming the range of your y-axis is known or can be calculated:
  y_max <- max(submission_detailed_df$businessMax, na.rm = TRUE)
  # Create a sequence from 1 to the maximum value of y, by 1 unit interval
  hlines <- seq(1, y_max, by = 1)
  # Add horizontal lines to the plot
  b_plot <- b_plot + geom_hline(yintercept = hlines, color = "white", linetype = "solid")
  
  e_plot <- ggplot(submission_detailed_df %>% filter(userKey == user), aes(x = factor(submissionCount))) +
    geom_bar(aes(y = environmentalMax), stat = "identity", fill = "gainsboro", position = position_dodge(width = dodge_width), width = bar_width) +
    geom_bar(aes(y = environmental), stat = "identity", fill = "forestgreen", position = position_dodge(width = dodge_width), width = bar_width) +
    labs(title = "Environmental",
         x = "submissionCount",
         y = "count",
         fill = "Variable") +
    theme_minimal()
  y_max <- max(submission_detailed_df$environmentalMax, na.rm = TRUE)
  hlines <- seq(1, y_max, by = 1)
  e_plot <- e_plot + geom_hline(yintercept = hlines, color = "white", linetype = "solid")
  
  c_plot <- ggplot(submission_detailed_df %>% filter(userKey == user), aes(x = factor(submissionCount))) +
    geom_bar(aes(y = communityMax), stat = "identity", fill = "gainsboro", position = position_dodge(width = dodge_width), width = bar_width) +
    geom_bar(aes(y = community), stat = "identity", fill = "darkorange", position = position_dodge(width = dodge_width), width = bar_width) +
    labs(title = "Community",
         x = "submissionCount",
         y = "count",
         fill = "Variable") +
    theme_minimal()
  y_max <- max(submission_detailed_df$communityMax, na.rm = TRUE)
  hlines <- seq(1, y_max, by = 1)
  c_plot <- c_plot + geom_hline(yintercept = hlines, color = "white", linetype = "solid")
  
  print((b_plot / e_plot / c_plot) +
    plot_annotation(title = user))
}

ONA Section

1. combine conservation and limited use and set self-connection to zero

which means luc_1_X + luc_4_X, luc_X_1 + luc_X_4

A_matrix_2 <- A_matrix
B_matrix_2 <- B_matrix
C_matrix_2 <- C_matrix
for (i in 1:11) {
  A_luc1x = which(names(A_matrix_2)==paste0("luc_", 1, "_", i-1))
  A_luc4x = which(names(A_matrix_2)==paste0("luc_", 4, "_", i-1))
  B_luc1x = which(names(B_matrix_2)==paste0("luc_", 1, "_", i-1))
  B_luc4x = which(names(B_matrix_2)==paste0("luc_", 4, "_", i-1))
  C_luc1x = which(names(C_matrix_2)==paste0("luc_", 1, "_", i-1))
  C_luc4x = which(names(C_matrix_2)==paste0("luc_", 4, "_", i-1))
  A_matrix_2[[A_luc1x]] <- A_matrix_2[[A_luc1x]] + A_matrix_2[[A_luc4x]]
  B_matrix_2[[B_luc1x]] <- B_matrix_2[[B_luc1x]] + B_matrix_2[[B_luc4x]]
  C_matrix_2[[C_luc1x]] <- C_matrix_2[[C_luc1x]] + C_matrix_2[[C_luc4x]]
}
for (i in 1:11) {
  A_lucx1 = which(names(A_matrix_2)==paste0("luc_", i-1, "_", 1))
  A_lucx4 = which(names(A_matrix_2)==paste0("luc_", i-1, "_", 4))
  B_lucx1 = which(names(B_matrix_2)==paste0("luc_", i-1, "_", 1))
  B_lucx4 = which(names(B_matrix_2)==paste0("luc_", i-1, "_", 4))
  C_lucx1 = which(names(C_matrix_2)==paste0("luc_", i-1, "_", 1))
  C_lucx4 = which(names(C_matrix_2)==paste0("luc_", i-1, "_", 4))
  A_matrix_2[[A_lucx1]] <- A_matrix_2[[A_lucx1]] + A_matrix_2[[A_lucx4]]
  B_matrix_2[[B_lucx1]] <- B_matrix_2[[B_lucx1]] + B_matrix_2[[B_lucx4]]
  C_matrix_2[[C_lucx1]] <- C_matrix_2[[C_lucx1]] + C_matrix_2[[C_lucx4]]
}
for (i in 1:11) {
  A_lucxx = which(names(A_matrix_2)==paste0("luc_", i-1, "_", i-1))
  B_lucxx = which(names(B_matrix_2)==paste0("luc_", i-1, "_", i-1))
  C_lucxx = which(names(C_matrix_2)==paste0("luc_", i-1, "_", i-1))
  A_matrix_2[[A_lucxx]] = 0
  B_matrix_2[[B_lucxx]] = 0
  C_matrix_2[[C_lucxx]] = 0
}

A_matrix_2 <- A_matrix_2 %>% select(-c(luc_4_0, luc_4_1, luc_4_2, luc_4_3, luc_4_4, 
                               luc_4_5, luc_4_6, luc_4_7, luc_4_8, luc_4_9, luc_4_10,
                               luc_0_4, luc_1_4, luc_2_4, luc_3_4, luc_4_4,
                               luc_5_4, luc_6_4, luc_7_4, luc_8_4, luc_9_4, luc_10_4))
B_matrix_2 <- B_matrix_2 %>% select(-c(luc_4_0, luc_4_1, luc_4_2, luc_4_3, luc_4_4, 
                               luc_4_5, luc_4_6, luc_4_7, luc_4_8, luc_4_9, luc_4_10,
                               luc_0_4, luc_1_4, luc_2_4, luc_3_4, luc_4_4,
                               luc_5_4, luc_6_4, luc_7_4, luc_8_4, luc_9_4, luc_10_4))
C_matrix_2 <- C_matrix_2 %>% select(-c(luc_4_0, luc_4_1, luc_4_2, luc_4_3, luc_4_4, 
                               luc_4_5, luc_4_6, luc_4_7, luc_4_8, luc_4_9, luc_4_10,
                               luc_0_4, luc_1_4, luc_2_4, luc_3_4, luc_4_4,
                               luc_5_4, luc_6_4, luc_7_4, luc_8_4, luc_9_4, luc_10_4))

2. make ABC col names consistent for the ease of later work

colnames(A_matrix_2)[2] = "SH"
A_matrix_2 <- A_matrix_2 %>%
  select(-c(...1)) %>% 
  add_column(user_name = "NA", .before = "luc_0_0") %>%
  add_column(submission = "NA",.before = "luc_0_0") %>%
  add_column(index = 1:nrow(A_matrix), .before = "SH")
colnames(B_matrix_2)[2] = "SH"
B_matrix_2 <- B_matrix_2 %>%
  select(-c(...1)) %>% 
  add_column(user_name = "NA", .before = "luc_0_0") %>%
  add_column(submission = "NA",.before = "luc_0_0") %>%
  add_column(index = 1:nrow(B_matrix), .before = "SH")
C_matrix_2 <- C_matrix_2 %>%
  add_column(index = 1:nrow(C_matrix_2), .before = "user_name") %>%
  add_column(Name = "NA", .before = "user_name") %>%
  add_column(Satisfy = "NA",.before = "user_name") %>%
  add_column(N = "NA", .before = "user_name")

3.run ONA

call generate.ona.object function

generate.ona.object <- function(data, unit.col, meta.col, codes){
  output <- list()
  f.units <- unit.col
  ENA_UNIT <- rENA::merge_columns_c(f.units, cols = colnames(f.units));
  # ENA_UNIT <-  f.units
  f.raw <- data
  f.codes <- codes
  dena_data = directedENA:::ena.set.directed(f.raw, f.units, NA, f.codes)
  output.meta.data <- meta.col
  dena_data$meta.data <- data.table::as.data.table(cbind(ENA_UNIT, output.meta.data))
  for( i in colnames(dena_data$meta.data) ) {
    set(dena_data$meta.data, j = i, value = rENA::as.ena.metadata(dena_data$meta.data[[i]]))
  }
  code_length <- length(dena_data$rotation$codes);
  dena_data$rotation$adjacency.key <- data.table::data.table(matrix(c(
    rep(1:code_length, code_length),
    rep(1:code_length, each = code_length)),
    byrow = TRUE, nrow = 2
  ))
  directed.adjacency.vectors <- as.ena.matrix(data.table::as.data.table(data[, grep("V", colnames(data))]), "ena.connections")
  # aren't these two the same thing 
  dena_data$connection.counts <- data.table::as.data.table(cbind(dena_data$meta.data, directed.adjacency.vectors))
  dena_data$connection.counts = rENA::as.ena.matrix(x = dena_data$connection.counts, "ena.connections")
  for (i in which(!rENA::find_meta_cols(dena_data$connection.counts)))
    set(dena_data$connection.counts, j = i, value = as.ena.co.occurrence(as.double(dena_data$connection.counts[[i]])))
  dena_data$model$row.connection.counts = data.table::as.data.table(cbind(dena_data$meta.data, directed.adjacency.vectors))
  dena_data$model$row.connection.counts <- rENA::as.ena.matrix(dena_data$model$row.connection.counts, "row.connections")
  output = dena_data;
  return(output)
}
# 1. prepare df

# df <- A_matrix
# df <- B_matrix
df <- C_matrix_2

names(df)[7:106] <- paste0("V",seq(1:100))
df$mapid = mapid

# 2. accum
accumC <- generate.ona.object(
  df,
  unit.col = df[,1:7],
  meta.col = df[,1:7],
  codes = as.vector(
    c("Commercial",
    "Conservation_lu",
    # "Conservation",
    "Cropland",
    "Industrial",
    # "Limited Use",
    "Pasture",
    "Recreation",
    "Residential HD",
    "Residential LD",
    "Timber",
    "Wetlands")))

# 3. model
setC <- model(accumC)

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution

warning: solve(): system is singular; attempting approx solution
# 4. GoF
correlations(setC)
NA
# 1. prepare df

df1 <- A_matrix_2
# df <- B_matrix
# df <- C_matrix

names(df1)[7:106] <- paste0("V",seq(1:100))
df1$mapid = mapid

# 2. accum
accumA <- generate.ona.object(
  df1,
  unit.col = df1[,1:7],
  meta.col = df1[,1:7],
  codes = as.vector(
    c("Commercial",
    "Conservation_lu",
    # "Conservation",
    "Cropland",
    "Industrial",
    # "Limited Use",
    "Pasture",
    "Recreation",
    "Residential HD",
    "Residential LD",
    "Timber",
    "Wetlands")))

# 3. model
setA <- model(accumA)

# 4. GoF
correlations(setA)

4. project C points into A space

To do so, I need to make a set using C’s accumulation and A’s rotation matrix

set=model(accumC, rotation.set = setA$rotation)

5. ona plotting

5.1 setting global visual parameters here so that all ONA plots we generate are on the same scale

node_size_multiplier = 0.2
node_position_multiplier = 1.0
edge_size_multiplier = 0.2
point_position_multiplier = 1.0
edge_arrow_saturation_multiplier = 1.0
ona:::plot.ena.ordered.set(setC) %>% 
  units( 
    points = setC$points,
    points_color = "black",
    show_mean = FALSE, show_points = TRUE, with_ci = FALSE)

5.2 quick check points ARE being rotated

ona:::plot.ena.ordered.set(setA, title = "space used for projection and its points") %>%
  units(
    points = setA$points,
    points_color = "gray",
    show_mean = TRUE, show_points = TRUE, with_ci = FALSE) %>%
 nodes(
    node_size_multiplier = 0.001) 

ona:::plot.ena.ordered.set(setC, title = "points need to be projected in its original space") %>%
  units( 
    points = setC$points,
    points_color = "black",
    show_mean = FALSE, show_points = TRUE, with_ci = FALSE)%>%
 nodes(
    node_size_multiplier = 0.001) 

ona:::plot.ena.ordered.set(set, title = "projected points in its new space") %>%
  units(
    points = set$points,
    points_color = "black",
    show_mean = FALSE, show_points = TRUE, with_ci = FALSE) %>%
  units(
    points = setA$points,
    points_color = "gray",
    show_mean = FALSE, show_points = TRUE, with_ci = FALSE) %>%
 nodes(
    node_size_multiplier = 0.001) 

Cluster Check:

ona:::plot.ena.ordered.set(setA, title = "space used for projection and its points") %>%
  units(
    points = setA$points,
    points_color = "gray",
    show_mean = TRUE, show_points = TRUE, with_ci = FALSE) %>%
 nodes(
    node_size_multiplier = 0.001) 
A = setA$points[ENA_DIRECTION== 'response']

Plot both bar plots and ona plots by specifying user

uniqueUsers_filtered
  [1] "AidanPereira"                                    "Aiden"                                          
  [3] "AidenD"                                          "AidenDawley"                                    
  [5] "Alexa"                                           "Alysiah"                                        
  [7] "Amanda"                                          "Angelina123"                                    
  [9] "AnthonyD"                                        "Ariana_25"                                      
 [11] "Aswafford25"                                     "AubreyH"                                        
 [13] "Autumn"                                          "AydenH"                                         
 [15] "BryceG13"                                        "Caden"                                          
 [17] "Caitlin"                                         "ChaseB."                                        
 [19] "Cole"                                            "Colin_Danko_25"                                 
 [21] "Collin"                                          "ConnorHogan"                                    
 [23] "Cstpierre"                                       "D4v0nt43"                                       
 [25] "Daniel"                                          "DavidGa"                                        
 [27] "Deandre"                                         "DonutD4V0NT43"                                  
 [29] "DylanJodoin123"                                  "EdgarP"                                         
 [31] "EdgarP190"                                       "Elijah25"                                       
 [33] "Emmanewberg"                                     "Eric"                                           
 [35] "EricaP"                                          "Esaraiva"                                       
 [37] "EthanTaylor25"                                   "GabeS"                                          
 [39] "Grace"                                           "HaileyP"                                        
 [41] "HannahSorel"                                     "HectorMajor"                                    
 [43] "Hunter"                                          "HunterK"                                        
 [45] "Isabella"                                        "JacksonK"                                       
 [47] "Jada"                                            "JaredL"                                         
 [49] "Jayna"                                           "Jenniferfall"                                   
 [51] "JeremyS"                                         "JettB"                                          
 [53] "Jordan"                                          "Kabaia"                                         
 [55] "Kabaiaa"                                         "KylieF"                                         
 [57] "Leyla"                                           "Lila"                                           
 [59] "Linnea"                                          "LoganM22"                                       
 [61] "Makaylah23"                                      "Marcos"                                         
 [63] "Marcus25"                                        "Marlenyg"                                       
 [65] "MarquellMoniz25"                                 "Mayolifs"                                       
 [67] "Meghanmelo"                                      "Monicaking"                                     
 [69] "NathanG"                                         "Nathen"                                         
 [71] "Neves7C"                                         "NicholasP"                                      
 [73] "Nicoleoliveira"                                  "NolanKelly25"                                   
 [75] "Noleen"                                          "Oscar"                                          
 [77] "PaytonG14"                                       "Ryan"                                           
 [79] "Shawn"                                           "ShiMyers"                                       
 [81] "Sofia214Torres"                                  "SofiaTorres"                                    
 [83] "SophiaP"                                         "Synthia"                                        
 [85] "TannerD"                                         "Taylorg1209"                                    
 [87] "TekoaM"                                          "TekoaMyers"                                     
 [89] "Teyshann11"                                      "Tiffany"                                        
 [91] "TimmyTomlinson25"                                "Tony_lacen"                                     
 [93] "Travis"                                          "VictoriaB"                                      
 [95] "Zackary"                                         "[\\p{L}\\p{M}\\p{S}\\p{N}\\p{P}]+"              
 [97] "addisonboulris"                                  "alexn"                                          
 [99] "amyah131"                                        "amyaharidano13"                                 
[101] "anto.nella"                                      "audrie.ambeault"                                
[103] "butterfly"                                       "cole13"                                         
[105] "diego"                                           "emmguerra"                                      
[107] "giannasx3"                                       "gracie"                                         
[109] "graciel"                                         "hhaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
[111] "jazlynf"                                         "jodilamagna"                                    
[113] "joziah12"                                        "jsignorella"                                    
[115] "kasinrose1"                                      "mainmandiaw3545"                                
[117] "mohamed711"                                      "nchaber123"                                     
[119] "nicholaschaber"                                  "nick"                                           
[121] "rachaelbonner25"                                 "rboler25"                                       
[123] "robloxman225"                                   
userkey = "AidanPereira" # Change as appropriate

subs <- as.list(unique(set$points$ENA_UNIT))
subs <- subs[grepl(userkey, subs)] 
ona_plots <- list()

for (i in subs) {
  p <- ona:::plot.ena.ordered.set(set, title = paste0(i)) %>%
  edges(
      weights = set$line.weights[ENA_UNIT == i],
      edge_size_multiplier = edge_size_multiplier,
      edge_arrow_saturation_multiplier = edge_arrow_saturation_multiplier,
      node_position_multiplier = node_position_multiplier,
      edge_color = c("red")) %>%
  nodes(
    node_size_multiplier = node_size_multiplier,
    node_position_multiplier = node_position_multiplier,
    self_connection_color = "red")  %>%
  units(
      points=set$points[ENA_UNIT == i],
      points_color = "black",
      point_position_multiplier = point_position_multiplier,
      show_mean = FALSE, show_points = TRUE, with_ci = FALSE) %>%
  units(
      points = setA$points[SH == sh_name[1] & Satisfy == "Yes"],
      points_color = "green",
      point_position_multiplier = point_position_multiplier,
      show_mean = TRUE, show_points = FALSE, with_ci = FALSE) %>%
  units(
      points = setA$points[SH == sh_name[2] & Satisfy == "Yes"],
      points_color = "blue",
      point_position_multiplier = point_position_multiplier,
      show_mean = TRUE, show_points = FALSE, with_ci = FALSE) %>%
  units(
      points = setA$points[SH == sh_name[3] & Satisfy == "Yes"],
      points_color = "brown",
      point_position_multiplier = point_position_multiplier,
      show_mean = TRUE, show_points = FALSE, with_ci = FALSE) %>%
  units(
      points = setA$points[SH == sh_name[4] & Satisfy == "Yes"],
      points_color = "purple",
      point_position_multiplier = point_position_multiplier,
      show_mean = TRUE, show_points = FALSE, with_ci = FALSE) %>%
  units(
      points = setA$points[SH == sh_name[5] & Satisfy == "Yes"],
      points_color = "yellow",
      point_position_multiplier = point_position_multiplier,
      show_mean = TRUE, show_points = FALSE, with_ci = FALSE) %>%
  units(
      points = setA$points[SH == sh_name[6] & Satisfy == "Yes"],
      points_color = "deeppink",
      point_position_multiplier = point_position_multiplier,
      show_mean = TRUE, show_points = FALSE, with_ci = FALSE) %>%
  units(
      points = setA$points[SH == sh_name[7] & Satisfy == "Yes"],
      points_color = "Tan",
      point_position_multiplier = point_position_multiplier,
      show_mean = TRUE, show_points = FALSE, with_ci = FALSE) %>%
  units(
      points = setA$points[SH == sh_name[8] & Satisfy == "Yes"],
      points_color = "Cyan",
      point_position_multiplier = point_position_multiplier,
      show_mean = TRUE, show_points = FALSE, with_ci = FALSE) %>%
  units(
      points = setA$points[SH == sh_name[9] & Satisfy == "Yes"],
      points_color = "orange",
      point_position_multiplier = point_position_multiplier,
      show_mean = TRUE, show_points = FALSE, with_ci = FALSE)%>% 
      plotly::layout(showlegend = TRUE, legend = list(x = 100, y = 0.9)) %>% 
      style(name = "point", traces = c(2)) %>% 
    style(name = sh_info[1], traces = c(3)) %>% 
    style(name = sh_info[2], traces = c(4)) %>% 
    style(name = sh_info[3], traces = c(5)) %>% 
    style(name = sh_info[4], traces = c(6)) %>% 
    style(name = sh_info[5], traces = c(7)) %>% 
    style(name = sh_info[6], traces = c(8)) %>% 
    style(name = sh_info[7], traces = c(9)) %>% 
    style(name = sh_info[8], traces = c(10)) %>% 
    style(name = sh_info[9], traces = c(11))
  ona_plots[[i]] <- p
}
bar_width = 0.5
dodge_width <- 0  # Adjust this as needed
expand_mults <- c(0, 0.5)
submissionCount_levels <- as.character(unique(submission_detailed_df$submissionCount))

b_plot <- ggplot(submission_detailed_df %>% filter(userKey == userkey), aes(x = factor(submissionCount))) +
  geom_bar(aes(y = businessMax), stat = "identity", fill = "gainsboro", position = position_dodge(width = dodge_width), width = bar_width) +
  geom_bar(aes(y = business), stat = "identity", fill = "cornflowerblue", position = position_dodge(width = dodge_width), width = bar_width) +
  labs(title = "Business",
       x = "submissionCount",
       y = "count",
       fill = "Variable") +
  theme_minimal()
# +
#   scale_x_discrete(expand = expand_scale(mult = expand_mults, add = c(0, 0)))
# Assuming the range of your y-axis is known or can be calculated:
y_max <- max(submission_detailed_df$businessMax, na.rm = TRUE)
# Create a sequence from 1 to the maximum value of y, by 1 unit interval
hlines <- seq(1, y_max, by = 1)
# Add horizontal lines to the plot
b_plot <- b_plot + geom_hline(yintercept = hlines, color = "white", linetype = "solid")

e_plot <- ggplot(submission_detailed_df %>% filter(userKey == userkey), aes(x = factor(submissionCount))) +
  geom_bar(aes(y = environmentalMax), stat = "identity", fill = "gainsboro", position = position_dodge(width = dodge_width), width = bar_width) +
  geom_bar(aes(y = environmental), stat = "identity", fill = "forestgreen", position = position_dodge(width = dodge_width), width = bar_width) +
  labs(title = "Environmental",
       x = "submissionCount",
       y = "count",
       fill = "Variable") +
  theme_minimal()
y_max <- max(submission_detailed_df$environmentalMax, na.rm = TRUE)
hlines <- seq(1, y_max, by = 1)
e_plot <- e_plot + geom_hline(yintercept = hlines, color = "white", linetype = "solid")

c_plot <- ggplot(submission_detailed_df %>% filter(userKey == userkey), aes(x = factor(submissionCount))) +
  geom_bar(aes(y = communityMax), stat = "identity", fill = "gainsboro", position = position_dodge(width = dodge_width), width = bar_width) +
  geom_bar(aes(y = community), stat = "identity", fill = "darkorange", position = position_dodge(width = dodge_width), width = bar_width) +
  labs(title = "Community",
       x = "submissionCount",
       y = "count",
       fill = "Variable") +
  theme_minimal()
y_max <- max(submission_detailed_df$communityMax, na.rm = TRUE)
hlines <- seq(1, y_max, by = 1)
c_plot <- c_plot + geom_hline(yintercept = hlines, color = "white", linetype = "solid")

print((b_plot / e_plot / c_plot) +
  plot_annotation(title = userkey))


for (p in ona_plots) {
  print(p)
}
LS0tCnRpdGxlOiAiU3RvcnkgYW5hbHlzaXMgb2YgcGxheWVycyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9IAprbml0cjo6b3B0c19jaHVuayRzZXQod2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UpIApgYGAKCmBgYHtyfQpybShsaXN0ID0gbHMoKSkKIyBsaWJyYXJ5KCJyc3R1ZGlvYXBpIikKIyBzZXR3ZChkaXJuYW1lKGdldEFjdGl2ZURvY3VtZW50Q29udGV4dCgpJHBhdGgpKQpgYGAKClVuY29tbWVudCBhbmQgcnVuIHRoaXMgYmxvY2sgaWYgeW91IGhhdmVuJ3QgaGFkIHRoZXNlIHBhY2thZ2VzIGluc3RhbGxlZApgYGB7cn0KIyBpbnN0YWxsLnBhY2thZ2VzKCJvbmEiLCByZXBvcyA9IGMoImh0dHBzOi8vY3Jhbi5xZS1saWJzLm9yZyIsICJodHRwczovL2NyYW4ucnN0dWRpby5vcmciKSkKIyBpbnN0YWxsLnBhY2thZ2VzKCJ0bWEiLCByZXBvcyA9IGMoImh0dHBzOi8vY3Jhbi5xZS1saWJzLm9yZyIsICJodHRwczovL2NyYW4ucnN0dWRpby5vcmciKSkKIyBpbnN0YWxsLnBhY2thZ2VzKCJtYWdyaXR0ciIpCmBgYAoKYGBge3IgaW5jbHVkZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShvbmEpCmxpYnJhcnkodG1hKQpsaWJyYXJ5KG1hZ3JpdHRyKQpsaWJyYXJ5KHJFTkEpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHJlYWRyKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoZ2dmb3J0aWZ5KQpsaWJyYXJ5KGRhdGEudGFibGUpCmxpYnJhcnkoc3VwZXJoZWF0KQpsaWJyYXJ5KHJqc29uKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmxpYnJhcnkocmFuZG9tY29sb1IpCmxpYnJhcnkocmxpc3QpCmxpYnJhcnkod2Vic2hvdCkKbGlicmFyeShwYXRjaHdvcmspCmBgYAoKIyAwLiBzZXR0aW5nIHVwIGNvbnN0YW50IHZhcmlhYmxlcyAoY2hhbmdlIGFzIGFwcHJvcHJpYXRlKQpgYGB7cn0KIyBtYXBpZCA9ICIyMzIzMDEyOSIKbWFwaWQgPSAiMjEwNzgwMTUiCiMgbWFwaWQgPSAiMjQwOTY1MDQiCndkID0gcGFzdGUwKGdldHdkKCksICIvZGF0YS8iKQpgYGAKCiMgMC4gcmVhZCBBIEIgQyBtYXRyaWNlcyBhbmQgb3RoZXIgcmVsZXZhbnQgZGF0YQpgYGB7cn0KQV9tYXRyaXggPSByZWFkX2NzdihwYXN0ZTAod2QsIG1hcGlkLCAiX2FfbWF0cml4LmNzdiIpKQpCX21hdHJpeCA9IHJlYWRfY3N2KHBhc3RlMCh3ZCwgbWFwaWQsICJfYl9tYXRyaXguY3N2IikpCkNfbWF0cml4ID0gcmVhZC5jc3YocGFzdGUwKHdkLCBtYXBpZCwgIl9jX21hdHJpeC5jc3YiKSkKc2hfaW5mbyA9IHJlYWQuY3N2KHBhc3RlMCh3ZCwgIkxFTSB0ZXh0IC0gU3Rha2Vob2xkZXJzLmNzdiIpKQpBID0ganNvbmxpdGU6OnJlYWRfanNvbihwYXN0ZTAod2QsIG1hcGlkLCAiX2luaXRfbWFwLmpzb24iKSkKcmVwcyA9IGpzb25saXRlOjpyZWFkX2pzb24ocGFzdGUwKHdkLCBtYXBpZCwgIl9yZXBzLmpzb24iKSkKc3ViX3Jlc3VsdCA9IHJlYWRSRFMocGFzdGUwKHdkLCBtYXBpZCwgImFfc3ViX3Jlc3VsdF9uZXcucmRzIikpICNyZWNvcmQgc2F0aXNmeSBsZXZlbApgYGAKCmBgYHtyfQpzaF9uYW1lID0gQV9tYXRyaXggJT4lCiAgc2VsZWN0KGMoTmFtZSkpICU+JQogIHVuaXF1ZSgpICU+JQogIHB1bGwoKQpgYGAKCmBgYHtyfQpzaF9pbmZvID0gc2hfaW5mbyAlPiUgCiAgZmlsdGVyKE5hbWUgJWluJSBzaF9uYW1lKSAlPiUgCiAgYXJyYW5nZShtYXRjaChOYW1lLCBzaF9uYW1lKSkgJT4lIAogIHVuaXRlKCJTSGluZm8iLCBOYW1lOkRpcmVjdGlvbiwgcmVtb3ZlID0gVFJVRSkgJT4lIAogIHB1bGwoKQpgYGAKCmBgYHtyfQpuYW1lX2NvbCA9IHNoX25hbWUKaW5kX2NvbCA9IGMoKQpkaXJfY29sID0gYygpCmdyb3VwX2NvbCA9IGMoKQpmb3IgKGkgaW4gMTpsZW5ndGgoQSRpbmRpY2F0b3JzKSkgewogIGZvciAoaiBpbiAxOmxlbmd0aChBJGluZGljYXRvcnNbW2ldXSRzdGFrZWhvbGRlcnMpKSB7CiAgICBpbmRfY29sIDwtIGFwcGVuZChpbmRfY29sLCBBJGluZGljYXRvcnNbW2ldXSRzdGFrZWhvbGRlcnNbW2pdXSRpbmRLZXkpCiAgICBkaXJfY29sIDwtIGFwcGVuZChkaXJfY29sLCBBJGluZGljYXRvcnNbW2ldXSRzdGFrZWhvbGRlcnNbW2pdXSRkaXJlY3Rpb24pCiAgICBncm91cF9jb2wgPC0gYXBwZW5kKGdyb3VwX2NvbCwgQSRpbmRpY2F0b3JzW1tpXV0kc3Rha2Vob2xkZXJzW1tqXV0kc3Rha2Vob2xkZXJHcm91cCkKICB9Cn0Kc2hfZGYgPC0gZGF0YS5mcmFtZShuYW1lID0gbmFtZV9jb2wsIGluZGljYXRvciA9IGluZF9jb2wsIGRpcmVjdGlvbiA9IGRpcl9jb2wsIGdyb3VwID0gZ3JvdXBfY29sKQpzaF9kZgpgYGAKCmBgYHtyfQpidXNpbmVzcyA8LSBzaF9kZiAlPiUgZmlsdGVyKGdyb3VwID09ICJMb2NhbCBCdXNpbmVzcyBDb25zb3J0aXVtIikKYnVzaW5lc3MgPC0gYnVzaW5lc3MkbmFtZQplbnZpcm9ubWVudGFsIDwtIHNoX2RmICU+JSBmaWx0ZXIoZ3JvdXAgPT0gIkVudmlyb25tZW50YWwgSnVzdGljZSBDZW50ZXIiKQplbnZpcm9ubWVudGFsIDwtIGVudmlyb25tZW50YWwkbmFtZQpjb21tdW5pdHkgPC0gc2hfZGYgJT4lIGZpbHRlcihncm91cCA9PSAiQ29tbXVuaXR5IENvYWxpdGlvbiIpCmNvbW11bml0eSA8LSBjb21tdW5pdHkkbmFtZQpgYGAKCmBgYHtyfQpzdWJtaXNzaW9uX25hbWUgPSBDX21hdHJpeCR1c2VyX25hbWUKc3VibWlzc2lvbl9vcmRlciA9IGMoKQpzdWJfYXBwcm92YWxfY291bnQgPSBjKCkKc3ViX29yZGVyX251bT0gYygpCgoKZm9yIChpIGluIDE6bGVuZ3RoKHN1Yl9yZXN1bHQpKXsKICBzdWJtaXNzaW9uX29yZGVyID0gYXBwZW5kKHN1Ym1pc3Npb25fb3JkZXIsIHN1Yl9yZXN1bHRbW2ldXSR1c2VyS2V5KQogIHN1Yl9vcmRlcl9udW0gPSBhcHBlbmQoc3ViX29yZGVyX251bSwgc3ViX3Jlc3VsdFtbaV1dJHN1Ym1pc3Npb25Db3VudCkKICBzdWJfYXBwcm92YWxfY291bnQgPSBhcHBlbmQoc3ViX2FwcHJvdmFsX2NvdW50LCBzdWJfcmVzdWx0W1tpXV0kYXBwcm92YWxDb3VudCkKfQpgYGAKCmBgYHtyfQpzdWJtaXNzaW9uX2RmIDwtIGRhdGEuZnJhbWUodXNlcktleSA9IHN1Ym1pc3Npb25fb3JkZXIsIHN1Ym1pc3Npb25Db3VudCA9IHN1Yl9vcmRlcl9udW0sIGFwcHJvdmFsQ291bnQgPSBzdWJfYXBwcm92YWxfY291bnQpCnVuaXF1ZVVzZXJzIDwtIHVuaXF1ZShzdWJtaXNzaW9uX2RmJHVzZXJLZXkpCnByaW50KHN1Ym1pc3Npb25fZGYpCnByaW50KHVuaXF1ZVVzZXJzKQpgYGAKCkZpbHRlciBvbmx5IHVzZXJzIHdpdGggbW9yZSB0aGFuIDIgc3VibWlzc2lvbnMKYGBge3J9CnVuaXF1ZVVzZXJzX2ZpbHRlcmVkIDwtIHN1Ym1pc3Npb25fZGYgJT4lCiAgZ3JvdXBfYnkodXNlcktleSkgJT4lIAogIHN1bW1hcmlzZShDb3VudCA9IG4oKSkgJT4lCiAgZmlsdGVyKENvdW50ID4gMikKCnVuaXF1ZVVzZXJzX2ZpbHRlcmVkIDwtIHVuaXF1ZVVzZXJzX2ZpbHRlcmVkJHVzZXJLZXkKYGBgCgpgYGB7cn0KbnVtUGxvdHMgPC0gNyAjIGFkanVzdCBhcyBhcHByb3ByaWF0ZQpiYXRjaFNpemUgPC0gY2VpbGluZyhsZW5ndGgodW5pcXVlVXNlcnNfZmlsdGVyZWQpIC8gbnVtUGxvdHMpCgpmb3IgKGkgaW4gMTpudW1QbG90cykgewogIGJhdGNoIDwtIHN1Ym1pc3Npb25fZGYgJT4lIGZpbHRlcih1c2VyS2V5ICVpbiUgdW5pcXVlVXNlcnNfZmlsdGVyZWRbKCgoaS0xKSAqIGJhdGNoU2l6ZSkgKyAxKToobWluKGxlbmd0aCh1bmlxdWVVc2Vyc19maWx0ZXJlZCksIGkgKiBiYXRjaFNpemUpKV0pCiAgCiAgIyBDcmVhdGUgYSBsaW5lIHBsb3QgdXNpbmcgZ2dwbG90MgogIHAgPC0gZ2dwbG90KGJhdGNoLCBhZXMoeCA9IHN1Ym1pc3Npb25Db3VudCwgeSA9IGFwcHJvdmFsQ291bnQsIGNvbG9yID0gdXNlcktleSwgbGluZXR5cGUgPSB1c2VyS2V5KSkgKwogICAgZ2VvbV9saW5lKHNpemU9MSkgKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IDE6bnJvdyhzdWJtaXNzaW9uX2RmKSwgbGFiZWxzID0gMTpucm93KHN1Ym1pc3Npb25fZGYpLCBtaW5vcl9icmVha3MgPSBOVUxMKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIG1heChzdWJtaXNzaW9uX2RmJGFwcHJvdmFsQ291bnQpLCBieSA9IDEpLCBtaW5vcl9icmVha3MgPSBOVUxMKSArCiAgICB0aGVtZV9taW5pbWFsKCkKICBwcmludChwKQp9CmBgYAoKUHJlcGFyZSBkYXRhZnJhbWUgZm9yIHN0YWNrZWQgYmFycGxvdApgYGB7cn0Kc3VibWlzc2lvbl9kZXRhaWxlZF9kZiA8LSBkYXRhLmZyYW1lKHVzZXJLZXkgPSBjaGFyYWN0ZXIoKSwgc3VibWlzc2lvbkNvdW50ID0gaW50ZWdlcigpLCBidXNpbmVzcyA9IGludGVnZXIoKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ1c2luZXNzTWF4ID0gaW50ZWdlcigpLCBlbnZpcm9ubWVudGFsID0gaW50ZWdlcigpLCBlbnZpcm9ubWVudGFsTWF4ID0gaW50ZWdlcigpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tbXVuaXR5ID0gaW50ZWdlcigpLCBjb21tdW5pdHlNYXggPSBpbnRlZ2VyKCkpCmZvciAoaSBpbiAxOmxlbmd0aChzdWJfcmVzdWx0KSkgewogIGlmIChzdWJfcmVzdWx0W1tpXV0kdXNlcktleSAlaW4lIHVuaXF1ZVVzZXJzX2ZpbHRlcmVkKSB7CiAgICBiX21heCA9IHN1bShidXNpbmVzcyAlaW4lIHN1Yl9yZXN1bHRbW2ldXSRzdGFrZWhvbGRlcnMpCiAgICBlX21heCA9IHN1bShlbnZpcm9ubWVudGFsICVpbiUgc3ViX3Jlc3VsdFtbaV1dJHN0YWtlaG9sZGVycykKICAgIGNfbWF4ID0gc3VtKGNvbW11bml0eSAlaW4lIHN1Yl9yZXN1bHRbW2ldXSRzdGFrZWhvbGRlcnMpCiAgICBiX3NlbGVjdCA9IHN1Yl9yZXN1bHRbW2ldXSRzdGFrZWhvbGRlcnNbc3ViX3Jlc3VsdFtbaV1dJHN0YWtlaG9sZGVycyAlaW4lIGJ1c2luZXNzXQogICAgZV9zZWxlY3QgPSBzdWJfcmVzdWx0W1tpXV0kc3Rha2Vob2xkZXJzW3N1Yl9yZXN1bHRbW2ldXSRzdGFrZWhvbGRlcnMgJWluJSBlbnZpcm9ubWVudGFsXQogICAgY19zZWxlY3QgPSBzdWJfcmVzdWx0W1tpXV0kc3Rha2Vob2xkZXJzW3N1Yl9yZXN1bHRbW2ldXSRzdGFrZWhvbGRlcnMgJWluJSBjb21tdW5pdHldCiAgICBiX2NvdW50ID0gMAogICAgZV9jb3VudCA9IDAKICAgIGNfY291bnQgPSAwCiAgICBmb3IgKGIgaW4gYl9zZWxlY3QpIHsKICAgICAgYl9jb3VudCA9IGJfY291bnQgKyBzdWJfcmVzdWx0W1tpXV0kc3Rha2Vob2xkZXJBcHByb3ZhbFtbYl1dCiAgICB9CiAgICBmb3IgKGUgaW4gZV9zZWxlY3QpIHsKICAgICAgZV9jb3VudCA9IGVfY291bnQgKyBzdWJfcmVzdWx0W1tpXV0kc3Rha2Vob2xkZXJBcHByb3ZhbFtbZV1dCiAgICB9CiAgICBmb3IgKGMgaW4gY19zZWxlY3QpIHsKICAgICAgY19jb3VudCA9IGNfY291bnQgKyBzdWJfcmVzdWx0W1tpXV0kc3Rha2Vob2xkZXJBcHByb3ZhbFtbY11dCiAgICB9CiAgICBzdWJtaXNzaW9uX2RldGFpbGVkX2RmIDwtIHJiaW5kKHN1Ym1pc3Npb25fZGV0YWlsZWRfZGYsIGRhdGEuZnJhbWUodXNlcktleSA9IHN1Yl9yZXN1bHRbW2ldXSR1c2VyS2V5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWJtaXNzaW9uQ291bnQgPSBzdWJfcmVzdWx0W1tpXV0kc3VibWlzc2lvbkNvdW50LCBidXNpbmVzcyA9IGJfY291bnQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ1c2luZXNzTWF4ID0gYl9tYXgsIGVudmlyb25tZW50YWwgPSBlX2NvdW50LCBlbnZpcm9ubWVudGFsTWF4ID0gZV9tYXgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbW11bml0eSA9IGNfY291bnQsIGNvbW11bml0eU1heCA9IGNfbWF4KSkKICB9Cn0KCmBgYAoKCmBgYHtyfQpiYXJfd2lkdGggPSAwLjUKZG9kZ2Vfd2lkdGggPC0gMCAgIyBBZGp1c3QgdGhpcyBhcyBuZWVkZWQKZXhwYW5kX211bHRzIDwtIGMoMCwgMC41KQpzdWJtaXNzaW9uQ291bnRfbGV2ZWxzIDwtIGFzLmNoYXJhY3Rlcih1bmlxdWUoc3VibWlzc2lvbl9kZXRhaWxlZF9kZiRzdWJtaXNzaW9uQ291bnQpKQpmb3IgKHVzZXIgaW4gdW5pcXVlVXNlcnNfZmlsdGVyZWQpIHsKICBiX3Bsb3QgPC0gZ2dwbG90KHN1Ym1pc3Npb25fZGV0YWlsZWRfZGYgJT4lIGZpbHRlcih1c2VyS2V5ID09IHVzZXIpLCBhZXMoeCA9IGZhY3RvcihzdWJtaXNzaW9uQ291bnQpKSkgKwogICAgZ2VvbV9iYXIoYWVzKHkgPSBidXNpbmVzc01heCksIHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gImdhaW5zYm9ybyIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSBkb2RnZV93aWR0aCksIHdpZHRoID0gYmFyX3dpZHRoKSArCiAgICBnZW9tX2JhcihhZXMoeSA9IGJ1c2luZXNzKSwgc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiY29ybmZsb3dlcmJsdWUiLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gZG9kZ2Vfd2lkdGgpLCB3aWR0aCA9IGJhcl93aWR0aCkgKwogICAgbGFicyh0aXRsZSA9ICJCdXNpbmVzcyIsCiAgICAgICAgIHggPSAic3VibWlzc2lvbkNvdW50IiwKICAgICAgICAgeSA9ICJjb3VudCIsCiAgICAgICAgIGZpbGwgPSAiVmFyaWFibGUiKSArCiAgICB0aGVtZV9taW5pbWFsKCkKICAjICsKICAjICAgc2NhbGVfeF9kaXNjcmV0ZShleHBhbmQgPSBleHBhbmRfc2NhbGUobXVsdCA9IGV4cGFuZF9tdWx0cywgYWRkID0gYygwLCAwKSkpCiAgIyBBc3N1bWluZyB0aGUgcmFuZ2Ugb2YgeW91ciB5LWF4aXMgaXMga25vd24gb3IgY2FuIGJlIGNhbGN1bGF0ZWQ6CiAgeV9tYXggPC0gbWF4KHN1Ym1pc3Npb25fZGV0YWlsZWRfZGYkYnVzaW5lc3NNYXgsIG5hLnJtID0gVFJVRSkKICAjIENyZWF0ZSBhIHNlcXVlbmNlIGZyb20gMSB0byB0aGUgbWF4aW11bSB2YWx1ZSBvZiB5LCBieSAxIHVuaXQgaW50ZXJ2YWwKICBobGluZXMgPC0gc2VxKDEsIHlfbWF4LCBieSA9IDEpCiAgIyBBZGQgaG9yaXpvbnRhbCBsaW5lcyB0byB0aGUgcGxvdAogIGJfcGxvdCA8LSBiX3Bsb3QgKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBobGluZXMsIGNvbG9yID0gIndoaXRlIiwgbGluZXR5cGUgPSAic29saWQiKQogIAogIGVfcGxvdCA8LSBnZ3Bsb3Qoc3VibWlzc2lvbl9kZXRhaWxlZF9kZiAlPiUgZmlsdGVyKHVzZXJLZXkgPT0gdXNlciksIGFlcyh4ID0gZmFjdG9yKHN1Ym1pc3Npb25Db3VudCkpKSArCiAgICBnZW9tX2JhcihhZXMoeSA9IGVudmlyb25tZW50YWxNYXgpLCBzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJnYWluc2Jvcm8iLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gZG9kZ2Vfd2lkdGgpLCB3aWR0aCA9IGJhcl93aWR0aCkgKwogICAgZ2VvbV9iYXIoYWVzKHkgPSBlbnZpcm9ubWVudGFsKSwgc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiZm9yZXN0Z3JlZW4iLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gZG9kZ2Vfd2lkdGgpLCB3aWR0aCA9IGJhcl93aWR0aCkgKwogICAgbGFicyh0aXRsZSA9ICJFbnZpcm9ubWVudGFsIiwKICAgICAgICAgeCA9ICJzdWJtaXNzaW9uQ291bnQiLAogICAgICAgICB5ID0gImNvdW50IiwKICAgICAgICAgZmlsbCA9ICJWYXJpYWJsZSIpICsKICAgIHRoZW1lX21pbmltYWwoKQogIHlfbWF4IDwtIG1heChzdWJtaXNzaW9uX2RldGFpbGVkX2RmJGVudmlyb25tZW50YWxNYXgsIG5hLnJtID0gVFJVRSkKICBobGluZXMgPC0gc2VxKDEsIHlfbWF4LCBieSA9IDEpCiAgZV9wbG90IDwtIGVfcGxvdCArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGhsaW5lcywgY29sb3IgPSAid2hpdGUiLCBsaW5ldHlwZSA9ICJzb2xpZCIpCiAgCiAgY19wbG90IDwtIGdncGxvdChzdWJtaXNzaW9uX2RldGFpbGVkX2RmICU+JSBmaWx0ZXIodXNlcktleSA9PSB1c2VyKSwgYWVzKHggPSBmYWN0b3Ioc3VibWlzc2lvbkNvdW50KSkpICsKICAgIGdlb21fYmFyKGFlcyh5ID0gY29tbXVuaXR5TWF4KSwgc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiZ2FpbnNib3JvIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IGRvZGdlX3dpZHRoKSwgd2lkdGggPSBiYXJfd2lkdGgpICsKICAgIGdlb21fYmFyKGFlcyh5ID0gY29tbXVuaXR5KSwgc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiZGFya29yYW5nZSIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSBkb2RnZV93aWR0aCksIHdpZHRoID0gYmFyX3dpZHRoKSArCiAgICBsYWJzKHRpdGxlID0gIkNvbW11bml0eSIsCiAgICAgICAgIHggPSAic3VibWlzc2lvbkNvdW50IiwKICAgICAgICAgeSA9ICJjb3VudCIsCiAgICAgICAgIGZpbGwgPSAiVmFyaWFibGUiKSArCiAgICB0aGVtZV9taW5pbWFsKCkKICB5X21heCA8LSBtYXgoc3VibWlzc2lvbl9kZXRhaWxlZF9kZiRjb21tdW5pdHlNYXgsIG5hLnJtID0gVFJVRSkKICBobGluZXMgPC0gc2VxKDEsIHlfbWF4LCBieSA9IDEpCiAgY19wbG90IDwtIGNfcGxvdCArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGhsaW5lcywgY29sb3IgPSAid2hpdGUiLCBsaW5ldHlwZSA9ICJzb2xpZCIpCiAgCiAgcHJpbnQoKGJfcGxvdCAvIGVfcGxvdCAvIGNfcGxvdCkgKwogICAgcGxvdF9hbm5vdGF0aW9uKHRpdGxlID0gdXNlcikpCn0KYGBgCgojIyBPTkEgU2VjdGlvbgoKCgojIDEuIGNvbWJpbmUgY29uc2VydmF0aW9uIGFuZCBsaW1pdGVkIHVzZSBhbmQgc2V0IHNlbGYtY29ubmVjdGlvbiB0byB6ZXJvCndoaWNoIG1lYW5zIGx1Y18xX1ggKyBsdWNfNF9YLCBsdWNfWF8xICsgbHVjX1hfNApgYGB7cn0KQV9tYXRyaXhfMiA8LSBBX21hdHJpeApCX21hdHJpeF8yIDwtIEJfbWF0cml4CkNfbWF0cml4XzIgPC0gQ19tYXRyaXgKZm9yIChpIGluIDE6MTEpIHsKICBBX2x1YzF4ID0gd2hpY2gobmFtZXMoQV9tYXRyaXhfMik9PXBhc3RlMCgibHVjXyIsIDEsICJfIiwgaS0xKSkKICBBX2x1YzR4ID0gd2hpY2gobmFtZXMoQV9tYXRyaXhfMik9PXBhc3RlMCgibHVjXyIsIDQsICJfIiwgaS0xKSkKICBCX2x1YzF4ID0gd2hpY2gobmFtZXMoQl9tYXRyaXhfMik9PXBhc3RlMCgibHVjXyIsIDEsICJfIiwgaS0xKSkKICBCX2x1YzR4ID0gd2hpY2gobmFtZXMoQl9tYXRyaXhfMik9PXBhc3RlMCgibHVjXyIsIDQsICJfIiwgaS0xKSkKICBDX2x1YzF4ID0gd2hpY2gobmFtZXMoQ19tYXRyaXhfMik9PXBhc3RlMCgibHVjXyIsIDEsICJfIiwgaS0xKSkKICBDX2x1YzR4ID0gd2hpY2gobmFtZXMoQ19tYXRyaXhfMik9PXBhc3RlMCgibHVjXyIsIDQsICJfIiwgaS0xKSkKICBBX21hdHJpeF8yW1tBX2x1YzF4XV0gPC0gQV9tYXRyaXhfMltbQV9sdWMxeF1dICsgQV9tYXRyaXhfMltbQV9sdWM0eF1dCiAgQl9tYXRyaXhfMltbQl9sdWMxeF1dIDwtIEJfbWF0cml4XzJbW0JfbHVjMXhdXSArIEJfbWF0cml4XzJbW0JfbHVjNHhdXQogIENfbWF0cml4XzJbW0NfbHVjMXhdXSA8LSBDX21hdHJpeF8yW1tDX2x1YzF4XV0gKyBDX21hdHJpeF8yW1tDX2x1YzR4XV0KfQpmb3IgKGkgaW4gMToxMSkgewogIEFfbHVjeDEgPSB3aGljaChuYW1lcyhBX21hdHJpeF8yKT09cGFzdGUwKCJsdWNfIiwgaS0xLCAiXyIsIDEpKQogIEFfbHVjeDQgPSB3aGljaChuYW1lcyhBX21hdHJpeF8yKT09cGFzdGUwKCJsdWNfIiwgaS0xLCAiXyIsIDQpKQogIEJfbHVjeDEgPSB3aGljaChuYW1lcyhCX21hdHJpeF8yKT09cGFzdGUwKCJsdWNfIiwgaS0xLCAiXyIsIDEpKQogIEJfbHVjeDQgPSB3aGljaChuYW1lcyhCX21hdHJpeF8yKT09cGFzdGUwKCJsdWNfIiwgaS0xLCAiXyIsIDQpKQogIENfbHVjeDEgPSB3aGljaChuYW1lcyhDX21hdHJpeF8yKT09cGFzdGUwKCJsdWNfIiwgaS0xLCAiXyIsIDEpKQogIENfbHVjeDQgPSB3aGljaChuYW1lcyhDX21hdHJpeF8yKT09cGFzdGUwKCJsdWNfIiwgaS0xLCAiXyIsIDQpKQogIEFfbWF0cml4XzJbW0FfbHVjeDFdXSA8LSBBX21hdHJpeF8yW1tBX2x1Y3gxXV0gKyBBX21hdHJpeF8yW1tBX2x1Y3g0XV0KICBCX21hdHJpeF8yW1tCX2x1Y3gxXV0gPC0gQl9tYXRyaXhfMltbQl9sdWN4MV1dICsgQl9tYXRyaXhfMltbQl9sdWN4NF1dCiAgQ19tYXRyaXhfMltbQ19sdWN4MV1dIDwtIENfbWF0cml4XzJbW0NfbHVjeDFdXSArIENfbWF0cml4XzJbW0NfbHVjeDRdXQp9CmZvciAoaSBpbiAxOjExKSB7CiAgQV9sdWN4eCA9IHdoaWNoKG5hbWVzKEFfbWF0cml4XzIpPT1wYXN0ZTAoImx1Y18iLCBpLTEsICJfIiwgaS0xKSkKICBCX2x1Y3h4ID0gd2hpY2gobmFtZXMoQl9tYXRyaXhfMik9PXBhc3RlMCgibHVjXyIsIGktMSwgIl8iLCBpLTEpKQogIENfbHVjeHggPSB3aGljaChuYW1lcyhDX21hdHJpeF8yKT09cGFzdGUwKCJsdWNfIiwgaS0xLCAiXyIsIGktMSkpCiAgQV9tYXRyaXhfMltbQV9sdWN4eF1dID0gMAogIEJfbWF0cml4XzJbW0JfbHVjeHhdXSA9IDAKICBDX21hdHJpeF8yW1tDX2x1Y3h4XV0gPSAwCn0KCkFfbWF0cml4XzIgPC0gQV9tYXRyaXhfMiAlPiUgc2VsZWN0KC1jKGx1Y180XzAsIGx1Y180XzEsIGx1Y180XzIsIGx1Y180XzMsIGx1Y180XzQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbHVjXzRfNSwgbHVjXzRfNiwgbHVjXzRfNywgbHVjXzRfOCwgbHVjXzRfOSwgbHVjXzRfMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsdWNfMF80LCBsdWNfMV80LCBsdWNfMl80LCBsdWNfM180LCBsdWNfNF80LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbHVjXzVfNCwgbHVjXzZfNCwgbHVjXzdfNCwgbHVjXzhfNCwgbHVjXzlfNCwgbHVjXzEwXzQpKQpCX21hdHJpeF8yIDwtIEJfbWF0cml4XzIgJT4lIHNlbGVjdCgtYyhsdWNfNF8wLCBsdWNfNF8xLCBsdWNfNF8yLCBsdWNfNF8zLCBsdWNfNF80LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGx1Y180XzUsIGx1Y180XzYsIGx1Y180XzcsIGx1Y180XzgsIGx1Y180XzksIGx1Y180XzEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbHVjXzBfNCwgbHVjXzFfNCwgbHVjXzJfNCwgbHVjXzNfNCwgbHVjXzRfNCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGx1Y181XzQsIGx1Y182XzQsIGx1Y183XzQsIGx1Y184XzQsIGx1Y185XzQsIGx1Y18xMF80KSkKQ19tYXRyaXhfMiA8LSBDX21hdHJpeF8yICU+JSBzZWxlY3QoLWMobHVjXzRfMCwgbHVjXzRfMSwgbHVjXzRfMiwgbHVjXzRfMywgbHVjXzRfNCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsdWNfNF81LCBsdWNfNF82LCBsdWNfNF83LCBsdWNfNF84LCBsdWNfNF85LCBsdWNfNF8xMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGx1Y18wXzQsIGx1Y18xXzQsIGx1Y18yXzQsIGx1Y18zXzQsIGx1Y180XzQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsdWNfNV80LCBsdWNfNl80LCBsdWNfN180LCBsdWNfOF80LCBsdWNfOV80LCBsdWNfMTBfNCkpCmBgYAoKIyAyLiBtYWtlIEFCQyBjb2wgbmFtZXMgY29uc2lzdGVudCBmb3IgdGhlIGVhc2Ugb2YgbGF0ZXIgd29yawpgYGB7cn0KY29sbmFtZXMoQV9tYXRyaXhfMilbMl0gPSAiU0giCkFfbWF0cml4XzIgPC0gQV9tYXRyaXhfMiAlPiUKICBzZWxlY3QoLWMoLi4uMSkpICU+JSAKICBhZGRfY29sdW1uKHVzZXJfbmFtZSA9ICJOQSIsIC5iZWZvcmUgPSAibHVjXzBfMCIpICU+JQogIGFkZF9jb2x1bW4oc3VibWlzc2lvbiA9ICJOQSIsLmJlZm9yZSA9ICJsdWNfMF8wIikgJT4lCiAgYWRkX2NvbHVtbihpbmRleCA9IDE6bnJvdyhBX21hdHJpeCksIC5iZWZvcmUgPSAiU0giKQpgYGAKCmBgYHtyfQpjb2xuYW1lcyhCX21hdHJpeF8yKVsyXSA9ICJTSCIKQl9tYXRyaXhfMiA8LSBCX21hdHJpeF8yICU+JQogIHNlbGVjdCgtYyguLi4xKSkgJT4lIAogIGFkZF9jb2x1bW4odXNlcl9uYW1lID0gIk5BIiwgLmJlZm9yZSA9ICJsdWNfMF8wIikgJT4lCiAgYWRkX2NvbHVtbihzdWJtaXNzaW9uID0gIk5BIiwuYmVmb3JlID0gImx1Y18wXzAiKSAlPiUKICBhZGRfY29sdW1uKGluZGV4ID0gMTpucm93KEJfbWF0cml4KSwgLmJlZm9yZSA9ICJTSCIpCmBgYAoKYGBge3J9CkNfbWF0cml4XzIgPC0gQ19tYXRyaXhfMiAlPiUKICBhZGRfY29sdW1uKGluZGV4ID0gMTpucm93KENfbWF0cml4XzIpLCAuYmVmb3JlID0gInVzZXJfbmFtZSIpICU+JQogIGFkZF9jb2x1bW4oTmFtZSA9ICJOQSIsIC5iZWZvcmUgPSAidXNlcl9uYW1lIikgJT4lCiAgYWRkX2NvbHVtbihTYXRpc2Z5ID0gIk5BIiwuYmVmb3JlID0gInVzZXJfbmFtZSIpICU+JQogIGFkZF9jb2x1bW4oTiA9ICJOQSIsIC5iZWZvcmUgPSAidXNlcl9uYW1lIikKYGBgCgojIDMucnVuIE9OQQpjYWxsIGdlbmVyYXRlLm9uYS5vYmplY3QgZnVuY3Rpb24KYGBge3IgZ2VuZXJhdGUub25hLm9iamVjdH0KZ2VuZXJhdGUub25hLm9iamVjdCA8LSBmdW5jdGlvbihkYXRhLCB1bml0LmNvbCwgbWV0YS5jb2wsIGNvZGVzKXsKICBvdXRwdXQgPC0gbGlzdCgpCiAgZi51bml0cyA8LSB1bml0LmNvbAogIEVOQV9VTklUIDwtIHJFTkE6Om1lcmdlX2NvbHVtbnNfYyhmLnVuaXRzLCBjb2xzID0gY29sbmFtZXMoZi51bml0cykpOwogICMgRU5BX1VOSVQgPC0gIGYudW5pdHMKICBmLnJhdyA8LSBkYXRhCiAgZi5jb2RlcyA8LSBjb2RlcwogIGRlbmFfZGF0YSA9IGRpcmVjdGVkRU5BOjo6ZW5hLnNldC5kaXJlY3RlZChmLnJhdywgZi51bml0cywgTkEsIGYuY29kZXMpCiAgb3V0cHV0Lm1ldGEuZGF0YSA8LSBtZXRhLmNvbAogIGRlbmFfZGF0YSRtZXRhLmRhdGEgPC0gZGF0YS50YWJsZTo6YXMuZGF0YS50YWJsZShjYmluZChFTkFfVU5JVCwgb3V0cHV0Lm1ldGEuZGF0YSkpCiAgZm9yKCBpIGluIGNvbG5hbWVzKGRlbmFfZGF0YSRtZXRhLmRhdGEpICkgewogICAgc2V0KGRlbmFfZGF0YSRtZXRhLmRhdGEsIGogPSBpLCB2YWx1ZSA9IHJFTkE6OmFzLmVuYS5tZXRhZGF0YShkZW5hX2RhdGEkbWV0YS5kYXRhW1tpXV0pKQogIH0KICBjb2RlX2xlbmd0aCA8LSBsZW5ndGgoZGVuYV9kYXRhJHJvdGF0aW9uJGNvZGVzKTsKICBkZW5hX2RhdGEkcm90YXRpb24kYWRqYWNlbmN5LmtleSA8LSBkYXRhLnRhYmxlOjpkYXRhLnRhYmxlKG1hdHJpeChjKAogICAgcmVwKDE6Y29kZV9sZW5ndGgsIGNvZGVfbGVuZ3RoKSwKICAgIHJlcCgxOmNvZGVfbGVuZ3RoLCBlYWNoID0gY29kZV9sZW5ndGgpKSwKICAgIGJ5cm93ID0gVFJVRSwgbnJvdyA9IDIKICApKQogIGRpcmVjdGVkLmFkamFjZW5jeS52ZWN0b3JzIDwtIGFzLmVuYS5tYXRyaXgoZGF0YS50YWJsZTo6YXMuZGF0YS50YWJsZShkYXRhWywgZ3JlcCgiViIsIGNvbG5hbWVzKGRhdGEpKV0pLCAiZW5hLmNvbm5lY3Rpb25zIikKICAjIGFyZW4ndCB0aGVzZSB0d28gdGhlIHNhbWUgdGhpbmcgCiAgZGVuYV9kYXRhJGNvbm5lY3Rpb24uY291bnRzIDwtIGRhdGEudGFibGU6OmFzLmRhdGEudGFibGUoY2JpbmQoZGVuYV9kYXRhJG1ldGEuZGF0YSwgZGlyZWN0ZWQuYWRqYWNlbmN5LnZlY3RvcnMpKQogIGRlbmFfZGF0YSRjb25uZWN0aW9uLmNvdW50cyA9IHJFTkE6OmFzLmVuYS5tYXRyaXgoeCA9IGRlbmFfZGF0YSRjb25uZWN0aW9uLmNvdW50cywgImVuYS5jb25uZWN0aW9ucyIpCiAgZm9yIChpIGluIHdoaWNoKCFyRU5BOjpmaW5kX21ldGFfY29scyhkZW5hX2RhdGEkY29ubmVjdGlvbi5jb3VudHMpKSkKICAgIHNldChkZW5hX2RhdGEkY29ubmVjdGlvbi5jb3VudHMsIGogPSBpLCB2YWx1ZSA9IGFzLmVuYS5jby5vY2N1cnJlbmNlKGFzLmRvdWJsZShkZW5hX2RhdGEkY29ubmVjdGlvbi5jb3VudHNbW2ldXSkpKQogIGRlbmFfZGF0YSRtb2RlbCRyb3cuY29ubmVjdGlvbi5jb3VudHMgPSBkYXRhLnRhYmxlOjphcy5kYXRhLnRhYmxlKGNiaW5kKGRlbmFfZGF0YSRtZXRhLmRhdGEsIGRpcmVjdGVkLmFkamFjZW5jeS52ZWN0b3JzKSkKICBkZW5hX2RhdGEkbW9kZWwkcm93LmNvbm5lY3Rpb24uY291bnRzIDwtIHJFTkE6OmFzLmVuYS5tYXRyaXgoZGVuYV9kYXRhJG1vZGVsJHJvdy5jb25uZWN0aW9uLmNvdW50cywgInJvdy5jb25uZWN0aW9ucyIpCiAgb3V0cHV0ID0gZGVuYV9kYXRhOwogIHJldHVybihvdXRwdXQpCn0KYGBgCgpgYGB7cn0KIyAxLiBwcmVwYXJlIGRmCgojIGRmIDwtIEFfbWF0cml4CiMgZGYgPC0gQl9tYXRyaXgKZGYgPC0gQ19tYXRyaXhfMgoKbmFtZXMoZGYpWzc6MTA2XSA8LSBwYXN0ZTAoIlYiLHNlcSgxOjEwMCkpCmRmJG1hcGlkID0gbWFwaWQKCiMgMi4gYWNjdW0KYWNjdW1DIDwtIGdlbmVyYXRlLm9uYS5vYmplY3QoCiAgZGYsCiAgdW5pdC5jb2wgPSBkZlssMTo3XSwKICBtZXRhLmNvbCA9IGRmWywxOjddLAogIGNvZGVzID0gYXMudmVjdG9yKAogICAgYygiQ29tbWVyY2lhbCIsCiAgICAiQ29uc2VydmF0aW9uX2x1IiwKICAgICMgIkNvbnNlcnZhdGlvbiIsCiAgICAiQ3JvcGxhbmQiLAogICAgIkluZHVzdHJpYWwiLAogICAgIyAiTGltaXRlZCBVc2UiLAogICAgIlBhc3R1cmUiLAogICAgIlJlY3JlYXRpb24iLAogICAgIlJlc2lkZW50aWFsIEhEIiwKICAgICJSZXNpZGVudGlhbCBMRCIsCiAgICAiVGltYmVyIiwKICAgICJXZXRsYW5kcyIpKSkKCiMgMy4gbW9kZWwKc2V0QyA8LSBtb2RlbChhY2N1bUMpCgojIDQuIEdvRgpjb3JyZWxhdGlvbnMoc2V0QykKCmBgYAoKYGBge3J9CiMgMS4gcHJlcGFyZSBkZgoKZGYxIDwtIEFfbWF0cml4XzIKIyBkZiA8LSBCX21hdHJpeAojIGRmIDwtIENfbWF0cml4CgpuYW1lcyhkZjEpWzc6MTA2XSA8LSBwYXN0ZTAoIlYiLHNlcSgxOjEwMCkpCmRmMSRtYXBpZCA9IG1hcGlkCgojIDIuIGFjY3VtCmFjY3VtQSA8LSBnZW5lcmF0ZS5vbmEub2JqZWN0KAogIGRmMSwKICB1bml0LmNvbCA9IGRmMVssMTo3XSwKICBtZXRhLmNvbCA9IGRmMVssMTo3XSwKICBjb2RlcyA9IGFzLnZlY3RvcigKICAgIGMoIkNvbW1lcmNpYWwiLAogICAgIkNvbnNlcnZhdGlvbl9sdSIsCiAgICAjICJDb25zZXJ2YXRpb24iLAogICAgIkNyb3BsYW5kIiwKICAgICJJbmR1c3RyaWFsIiwKICAgICMgIkxpbWl0ZWQgVXNlIiwKICAgICJQYXN0dXJlIiwKICAgICJSZWNyZWF0aW9uIiwKICAgICJSZXNpZGVudGlhbCBIRCIsCiAgICAiUmVzaWRlbnRpYWwgTEQiLAogICAgIlRpbWJlciIsCiAgICAiV2V0bGFuZHMiKSkpCgojIDMuIG1vZGVsCnNldEEgPC0gbW9kZWwoYWNjdW1BKQoKIyA0LiBHb0YKY29ycmVsYXRpb25zKHNldEEpCmBgYAoKIyA0LiBwcm9qZWN0IEMgcG9pbnRzIGludG8gQSBzcGFjZQpUbyBkbyBzbywgSSBuZWVkIHRvIG1ha2UgYSBzZXQgdXNpbmcgQydzIGFjY3VtdWxhdGlvbiBhbmQgQSdzIHJvdGF0aW9uIG1hdHJpeApgYGB7cn0Kc2V0PW1vZGVsKGFjY3VtQywgcm90YXRpb24uc2V0ID0gc2V0QSRyb3RhdGlvbikKYGBgCgojIDUuIG9uYSBwbG90dGluZyAKIyMgNS4xIHNldHRpbmcgZ2xvYmFsIHZpc3VhbCBwYXJhbWV0ZXJzIGhlcmUgc28gdGhhdCBhbGwgT05BIHBsb3RzIHdlIGdlbmVyYXRlIGFyZSBvbiB0aGUgc2FtZSBzY2FsZQpgYGB7cn0Kbm9kZV9zaXplX211bHRpcGxpZXIgPSAwLjIKbm9kZV9wb3NpdGlvbl9tdWx0aXBsaWVyID0gMS4wCmVkZ2Vfc2l6ZV9tdWx0aXBsaWVyID0gMC4yCnBvaW50X3Bvc2l0aW9uX211bHRpcGxpZXIgPSAxLjAKZWRnZV9hcnJvd19zYXR1cmF0aW9uX211bHRpcGxpZXIgPSAxLjAKYGBgCgpgYGB7cn0Kb25hOjo6cGxvdC5lbmEub3JkZXJlZC5zZXQoc2V0QykgJT4lIAogIHVuaXRzKCAKICAgIHBvaW50cyA9IHNldEMkcG9pbnRzLAogICAgcG9pbnRzX2NvbG9yID0gImJsYWNrIiwKICAgIHNob3dfbWVhbiA9IEZBTFNFLCBzaG93X3BvaW50cyA9IFRSVUUsIHdpdGhfY2kgPSBGQUxTRSkKYGBgCgojIyA1LjIgcXVpY2sgY2hlY2sgcG9pbnRzIEFSRSBiZWluZyByb3RhdGVkCmBgYHtyfQpvbmE6OjpwbG90LmVuYS5vcmRlcmVkLnNldChzZXRBLCB0aXRsZSA9ICJzcGFjZSB1c2VkIGZvciBwcm9qZWN0aW9uIGFuZCBpdHMgcG9pbnRzIikgJT4lCiAgdW5pdHMoCiAgICBwb2ludHMgPSBzZXRBJHBvaW50cywKICAgIHBvaW50c19jb2xvciA9ICJncmF5IiwKICAgIHNob3dfbWVhbiA9IFRSVUUsIHNob3dfcG9pbnRzID0gVFJVRSwgd2l0aF9jaSA9IEZBTFNFKSAlPiUKIG5vZGVzKAogICAgbm9kZV9zaXplX211bHRpcGxpZXIgPSAwLjAwMSkgCgpvbmE6OjpwbG90LmVuYS5vcmRlcmVkLnNldChzZXRDLCB0aXRsZSA9ICJwb2ludHMgbmVlZCB0byBiZSBwcm9qZWN0ZWQgaW4gaXRzIG9yaWdpbmFsIHNwYWNlIikgJT4lCiAgdW5pdHMoIAogICAgcG9pbnRzID0gc2V0QyRwb2ludHMsCiAgICBwb2ludHNfY29sb3IgPSAiYmxhY2siLAogICAgc2hvd19tZWFuID0gRkFMU0UsIHNob3dfcG9pbnRzID0gVFJVRSwgd2l0aF9jaSA9IEZBTFNFKSU+JQogbm9kZXMoCiAgICBub2RlX3NpemVfbXVsdGlwbGllciA9IDAuMDAxKSAKCm9uYTo6OnBsb3QuZW5hLm9yZGVyZWQuc2V0KHNldCwgdGl0bGUgPSAicHJvamVjdGVkIHBvaW50cyBpbiBpdHMgbmV3IHNwYWNlIikgJT4lCiAgdW5pdHMoCiAgICBwb2ludHMgPSBzZXQkcG9pbnRzLAogICAgcG9pbnRzX2NvbG9yID0gImJsYWNrIiwKICAgIHNob3dfbWVhbiA9IEZBTFNFLCBzaG93X3BvaW50cyA9IFRSVUUsIHdpdGhfY2kgPSBGQUxTRSkgJT4lCiAgdW5pdHMoCiAgICBwb2ludHMgPSBzZXRBJHBvaW50cywKICAgIHBvaW50c19jb2xvciA9ICJncmF5IiwKICAgIHNob3dfbWVhbiA9IEZBTFNFLCBzaG93X3BvaW50cyA9IFRSVUUsIHdpdGhfY2kgPSBGQUxTRSkgJT4lCiBub2RlcygKICAgIG5vZGVfc2l6ZV9tdWx0aXBsaWVyID0gMC4wMDEpIApgYGAKCiMjIENsdXN0ZXIgQ2hlY2s6CgoKYGBge3J9Cm9uYTo6OnBsb3QuZW5hLm9yZGVyZWQuc2V0KHNldEEsIHRpdGxlID0gInNwYWNlIHVzZWQgZm9yIHByb2plY3Rpb24gYW5kIGl0cyBwb2ludHMiKSAlPiUKICB1bml0cygKICAgIHBvaW50cyA9IHNldEEkcG9pbnRzLAogICAgcG9pbnRzX2NvbG9yID0gImdyYXkiLAogICAgc2hvd19tZWFuID0gVFJVRSwgc2hvd19wb2ludHMgPSBUUlVFLCB3aXRoX2NpID0gRkFMU0UpICU+JQogbm9kZXMoCiAgICBub2RlX3NpemVfbXVsdGlwbGllciA9IDAuMDAxKSAKYGBgCgpgYGB7cn0KQSA9IHNldEEkcG9pbnRzW0VOQV9ESVJFQ1RJT049PSAncmVzcG9uc2UnXQpgYGAKClBsb3QgYm90aCBiYXIgcGxvdHMgYW5kIG9uYSBwbG90cyBieSBzcGVjaWZ5aW5nIHVzZXIKCmBgYHtyfQp1bmlxdWVVc2Vyc19maWx0ZXJlZApgYGAKCmBgYHtyfQp1c2Vya2V5ID0gIkFpZGFuUGVyZWlyYSIgIyBDaGFuZ2UgYXMgYXBwcm9wcmlhdGUKCnN1YnMgPC0gYXMubGlzdCh1bmlxdWUoc2V0JHBvaW50cyRFTkFfVU5JVCkpCnN1YnMgPC0gc3Vic1tncmVwbCh1c2Vya2V5LCBzdWJzKV0gCm9uYV9wbG90cyA8LSBsaXN0KCkKCmZvciAoaSBpbiBzdWJzKSB7CiAgcCA8LSBvbmE6OjpwbG90LmVuYS5vcmRlcmVkLnNldChzZXQsIHRpdGxlID0gcGFzdGUwKGkpKSAlPiUKICBlZGdlcygKICAgICAgd2VpZ2h0cyA9IHNldCRsaW5lLndlaWdodHNbRU5BX1VOSVQgPT0gaV0sCiAgICAgIGVkZ2Vfc2l6ZV9tdWx0aXBsaWVyID0gZWRnZV9zaXplX211bHRpcGxpZXIsCiAgICAgIGVkZ2VfYXJyb3dfc2F0dXJhdGlvbl9tdWx0aXBsaWVyID0gZWRnZV9hcnJvd19zYXR1cmF0aW9uX211bHRpcGxpZXIsCiAgICAgIG5vZGVfcG9zaXRpb25fbXVsdGlwbGllciA9IG5vZGVfcG9zaXRpb25fbXVsdGlwbGllciwKICAgICAgZWRnZV9jb2xvciA9IGMoInJlZCIpKSAlPiUKICBub2RlcygKICAgIG5vZGVfc2l6ZV9tdWx0aXBsaWVyID0gbm9kZV9zaXplX211bHRpcGxpZXIsCiAgICBub2RlX3Bvc2l0aW9uX211bHRpcGxpZXIgPSBub2RlX3Bvc2l0aW9uX211bHRpcGxpZXIsCiAgICBzZWxmX2Nvbm5lY3Rpb25fY29sb3IgPSAicmVkIikgICU+JQogIHVuaXRzKAogICAgICBwb2ludHM9c2V0JHBvaW50c1tFTkFfVU5JVCA9PSBpXSwKICAgICAgcG9pbnRzX2NvbG9yID0gImJsYWNrIiwKICAgICAgcG9pbnRfcG9zaXRpb25fbXVsdGlwbGllciA9IHBvaW50X3Bvc2l0aW9uX211bHRpcGxpZXIsCiAgICAgIHNob3dfbWVhbiA9IEZBTFNFLCBzaG93X3BvaW50cyA9IFRSVUUsIHdpdGhfY2kgPSBGQUxTRSkgJT4lCiAgdW5pdHMoCiAgICAgIHBvaW50cyA9IHNldEEkcG9pbnRzW1NIID09IHNoX25hbWVbMV0gJiBTYXRpc2Z5ID09ICJZZXMiXSwKICAgICAgcG9pbnRzX2NvbG9yID0gImdyZWVuIiwKICAgICAgcG9pbnRfcG9zaXRpb25fbXVsdGlwbGllciA9IHBvaW50X3Bvc2l0aW9uX211bHRpcGxpZXIsCiAgICAgIHNob3dfbWVhbiA9IFRSVUUsIHNob3dfcG9pbnRzID0gRkFMU0UsIHdpdGhfY2kgPSBGQUxTRSkgJT4lCiAgdW5pdHMoCiAgICAgIHBvaW50cyA9IHNldEEkcG9pbnRzW1NIID09IHNoX25hbWVbMl0gJiBTYXRpc2Z5ID09ICJZZXMiXSwKICAgICAgcG9pbnRzX2NvbG9yID0gImJsdWUiLAogICAgICBwb2ludF9wb3NpdGlvbl9tdWx0aXBsaWVyID0gcG9pbnRfcG9zaXRpb25fbXVsdGlwbGllciwKICAgICAgc2hvd19tZWFuID0gVFJVRSwgc2hvd19wb2ludHMgPSBGQUxTRSwgd2l0aF9jaSA9IEZBTFNFKSAlPiUKICB1bml0cygKICAgICAgcG9pbnRzID0gc2V0QSRwb2ludHNbU0ggPT0gc2hfbmFtZVszXSAmIFNhdGlzZnkgPT0gIlllcyJdLAogICAgICBwb2ludHNfY29sb3IgPSAiYnJvd24iLAogICAgICBwb2ludF9wb3NpdGlvbl9tdWx0aXBsaWVyID0gcG9pbnRfcG9zaXRpb25fbXVsdGlwbGllciwKICAgICAgc2hvd19tZWFuID0gVFJVRSwgc2hvd19wb2ludHMgPSBGQUxTRSwgd2l0aF9jaSA9IEZBTFNFKSAlPiUKICB1bml0cygKICAgICAgcG9pbnRzID0gc2V0QSRwb2ludHNbU0ggPT0gc2hfbmFtZVs0XSAmIFNhdGlzZnkgPT0gIlllcyJdLAogICAgICBwb2ludHNfY29sb3IgPSAicHVycGxlIiwKICAgICAgcG9pbnRfcG9zaXRpb25fbXVsdGlwbGllciA9IHBvaW50X3Bvc2l0aW9uX211bHRpcGxpZXIsCiAgICAgIHNob3dfbWVhbiA9IFRSVUUsIHNob3dfcG9pbnRzID0gRkFMU0UsIHdpdGhfY2kgPSBGQUxTRSkgJT4lCiAgdW5pdHMoCiAgICAgIHBvaW50cyA9IHNldEEkcG9pbnRzW1NIID09IHNoX25hbWVbNV0gJiBTYXRpc2Z5ID09ICJZZXMiXSwKICAgICAgcG9pbnRzX2NvbG9yID0gInllbGxvdyIsCiAgICAgIHBvaW50X3Bvc2l0aW9uX211bHRpcGxpZXIgPSBwb2ludF9wb3NpdGlvbl9tdWx0aXBsaWVyLAogICAgICBzaG93X21lYW4gPSBUUlVFLCBzaG93X3BvaW50cyA9IEZBTFNFLCB3aXRoX2NpID0gRkFMU0UpICU+JQogIHVuaXRzKAogICAgICBwb2ludHMgPSBzZXRBJHBvaW50c1tTSCA9PSBzaF9uYW1lWzZdICYgU2F0aXNmeSA9PSAiWWVzIl0sCiAgICAgIHBvaW50c19jb2xvciA9ICJkZWVwcGluayIsCiAgICAgIHBvaW50X3Bvc2l0aW9uX211bHRpcGxpZXIgPSBwb2ludF9wb3NpdGlvbl9tdWx0aXBsaWVyLAogICAgICBzaG93X21lYW4gPSBUUlVFLCBzaG93X3BvaW50cyA9IEZBTFNFLCB3aXRoX2NpID0gRkFMU0UpICU+JQogIHVuaXRzKAogICAgICBwb2ludHMgPSBzZXRBJHBvaW50c1tTSCA9PSBzaF9uYW1lWzddICYgU2F0aXNmeSA9PSAiWWVzIl0sCiAgICAgIHBvaW50c19jb2xvciA9ICJUYW4iLAogICAgICBwb2ludF9wb3NpdGlvbl9tdWx0aXBsaWVyID0gcG9pbnRfcG9zaXRpb25fbXVsdGlwbGllciwKICAgICAgc2hvd19tZWFuID0gVFJVRSwgc2hvd19wb2ludHMgPSBGQUxTRSwgd2l0aF9jaSA9IEZBTFNFKSAlPiUKICB1bml0cygKICAgICAgcG9pbnRzID0gc2V0QSRwb2ludHNbU0ggPT0gc2hfbmFtZVs4XSAmIFNhdGlzZnkgPT0gIlllcyJdLAogICAgICBwb2ludHNfY29sb3IgPSAiQ3lhbiIsCiAgICAgIHBvaW50X3Bvc2l0aW9uX211bHRpcGxpZXIgPSBwb2ludF9wb3NpdGlvbl9tdWx0aXBsaWVyLAogICAgICBzaG93X21lYW4gPSBUUlVFLCBzaG93X3BvaW50cyA9IEZBTFNFLCB3aXRoX2NpID0gRkFMU0UpICU+JQogIHVuaXRzKAogICAgICBwb2ludHMgPSBzZXRBJHBvaW50c1tTSCA9PSBzaF9uYW1lWzldICYgU2F0aXNmeSA9PSAiWWVzIl0sCiAgICAgIHBvaW50c19jb2xvciA9ICJvcmFuZ2UiLAogICAgICBwb2ludF9wb3NpdGlvbl9tdWx0aXBsaWVyID0gcG9pbnRfcG9zaXRpb25fbXVsdGlwbGllciwKICAgICAgc2hvd19tZWFuID0gVFJVRSwgc2hvd19wb2ludHMgPSBGQUxTRSwgd2l0aF9jaSA9IEZBTFNFKSU+JSAKICAgICAgcGxvdGx5OjpsYXlvdXQoc2hvd2xlZ2VuZCA9IFRSVUUsIGxlZ2VuZCA9IGxpc3QoeCA9IDEwMCwgeSA9IDAuOSkpICU+JSAKICAgICAgc3R5bGUobmFtZSA9ICJwb2ludCIsIHRyYWNlcyA9IGMoMikpICU+JSAKICAgIHN0eWxlKG5hbWUgPSBzaF9pbmZvWzFdLCB0cmFjZXMgPSBjKDMpKSAlPiUgCiAgICBzdHlsZShuYW1lID0gc2hfaW5mb1syXSwgdHJhY2VzID0gYyg0KSkgJT4lIAogICAgc3R5bGUobmFtZSA9IHNoX2luZm9bM10sIHRyYWNlcyA9IGMoNSkpICU+JSAKICAgIHN0eWxlKG5hbWUgPSBzaF9pbmZvWzRdLCB0cmFjZXMgPSBjKDYpKSAlPiUgCiAgICBzdHlsZShuYW1lID0gc2hfaW5mb1s1XSwgdHJhY2VzID0gYyg3KSkgJT4lIAogICAgc3R5bGUobmFtZSA9IHNoX2luZm9bNl0sIHRyYWNlcyA9IGMoOCkpICU+JSAKICAgIHN0eWxlKG5hbWUgPSBzaF9pbmZvWzddLCB0cmFjZXMgPSBjKDkpKSAlPiUgCiAgICBzdHlsZShuYW1lID0gc2hfaW5mb1s4XSwgdHJhY2VzID0gYygxMCkpICU+JSAKICAgIHN0eWxlKG5hbWUgPSBzaF9pbmZvWzldLCB0cmFjZXMgPSBjKDExKSkKICBvbmFfcGxvdHNbW2ldXSA8LSBwCn0KCmBgYAoKYGBge3J9CmJhcl93aWR0aCA9IDAuNQpkb2RnZV93aWR0aCA8LSAwICAjIEFkanVzdCB0aGlzIGFzIG5lZWRlZApleHBhbmRfbXVsdHMgPC0gYygwLCAwLjUpCnN1Ym1pc3Npb25Db3VudF9sZXZlbHMgPC0gYXMuY2hhcmFjdGVyKHVuaXF1ZShzdWJtaXNzaW9uX2RldGFpbGVkX2RmJHN1Ym1pc3Npb25Db3VudCkpCgpiX3Bsb3QgPC0gZ2dwbG90KHN1Ym1pc3Npb25fZGV0YWlsZWRfZGYgJT4lIGZpbHRlcih1c2VyS2V5ID09IHVzZXJrZXkpLCBhZXMoeCA9IGZhY3RvcihzdWJtaXNzaW9uQ291bnQpKSkgKwogIGdlb21fYmFyKGFlcyh5ID0gYnVzaW5lc3NNYXgpLCBzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJnYWluc2Jvcm8iLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gZG9kZ2Vfd2lkdGgpLCB3aWR0aCA9IGJhcl93aWR0aCkgKwogIGdlb21fYmFyKGFlcyh5ID0gYnVzaW5lc3MpLCBzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJjb3JuZmxvd2VyYmx1ZSIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSBkb2RnZV93aWR0aCksIHdpZHRoID0gYmFyX3dpZHRoKSArCiAgbGFicyh0aXRsZSA9ICJCdXNpbmVzcyIsCiAgICAgICB4ID0gInN1Ym1pc3Npb25Db3VudCIsCiAgICAgICB5ID0gImNvdW50IiwKICAgICAgIGZpbGwgPSAiVmFyaWFibGUiKSArCiAgdGhlbWVfbWluaW1hbCgpCiMgKwojICAgc2NhbGVfeF9kaXNjcmV0ZShleHBhbmQgPSBleHBhbmRfc2NhbGUobXVsdCA9IGV4cGFuZF9tdWx0cywgYWRkID0gYygwLCAwKSkpCiMgQXNzdW1pbmcgdGhlIHJhbmdlIG9mIHlvdXIgeS1heGlzIGlzIGtub3duIG9yIGNhbiBiZSBjYWxjdWxhdGVkOgp5X21heCA8LSBtYXgoc3VibWlzc2lvbl9kZXRhaWxlZF9kZiRidXNpbmVzc01heCwgbmEucm0gPSBUUlVFKQojIENyZWF0ZSBhIHNlcXVlbmNlIGZyb20gMSB0byB0aGUgbWF4aW11bSB2YWx1ZSBvZiB5LCBieSAxIHVuaXQgaW50ZXJ2YWwKaGxpbmVzIDwtIHNlcSgxLCB5X21heCwgYnkgPSAxKQojIEFkZCBob3Jpem9udGFsIGxpbmVzIHRvIHRoZSBwbG90CmJfcGxvdCA8LSBiX3Bsb3QgKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBobGluZXMsIGNvbG9yID0gIndoaXRlIiwgbGluZXR5cGUgPSAic29saWQiKQoKZV9wbG90IDwtIGdncGxvdChzdWJtaXNzaW9uX2RldGFpbGVkX2RmICU+JSBmaWx0ZXIodXNlcktleSA9PSB1c2Vya2V5KSwgYWVzKHggPSBmYWN0b3Ioc3VibWlzc2lvbkNvdW50KSkpICsKICBnZW9tX2JhcihhZXMoeSA9IGVudmlyb25tZW50YWxNYXgpLCBzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJnYWluc2Jvcm8iLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gZG9kZ2Vfd2lkdGgpLCB3aWR0aCA9IGJhcl93aWR0aCkgKwogIGdlb21fYmFyKGFlcyh5ID0gZW52aXJvbm1lbnRhbCksIHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gImZvcmVzdGdyZWVuIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IGRvZGdlX3dpZHRoKSwgd2lkdGggPSBiYXJfd2lkdGgpICsKICBsYWJzKHRpdGxlID0gIkVudmlyb25tZW50YWwiLAogICAgICAgeCA9ICJzdWJtaXNzaW9uQ291bnQiLAogICAgICAgeSA9ICJjb3VudCIsCiAgICAgICBmaWxsID0gIlZhcmlhYmxlIikgKwogIHRoZW1lX21pbmltYWwoKQp5X21heCA8LSBtYXgoc3VibWlzc2lvbl9kZXRhaWxlZF9kZiRlbnZpcm9ubWVudGFsTWF4LCBuYS5ybSA9IFRSVUUpCmhsaW5lcyA8LSBzZXEoMSwgeV9tYXgsIGJ5ID0gMSkKZV9wbG90IDwtIGVfcGxvdCArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGhsaW5lcywgY29sb3IgPSAid2hpdGUiLCBsaW5ldHlwZSA9ICJzb2xpZCIpCgpjX3Bsb3QgPC0gZ2dwbG90KHN1Ym1pc3Npb25fZGV0YWlsZWRfZGYgJT4lIGZpbHRlcih1c2VyS2V5ID09IHVzZXJrZXkpLCBhZXMoeCA9IGZhY3RvcihzdWJtaXNzaW9uQ291bnQpKSkgKwogIGdlb21fYmFyKGFlcyh5ID0gY29tbXVuaXR5TWF4KSwgc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiZ2FpbnNib3JvIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IGRvZGdlX3dpZHRoKSwgd2lkdGggPSBiYXJfd2lkdGgpICsKICBnZW9tX2JhcihhZXMoeSA9IGNvbW11bml0eSksIHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gImRhcmtvcmFuZ2UiLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gZG9kZ2Vfd2lkdGgpLCB3aWR0aCA9IGJhcl93aWR0aCkgKwogIGxhYnModGl0bGUgPSAiQ29tbXVuaXR5IiwKICAgICAgIHggPSAic3VibWlzc2lvbkNvdW50IiwKICAgICAgIHkgPSAiY291bnQiLAogICAgICAgZmlsbCA9ICJWYXJpYWJsZSIpICsKICB0aGVtZV9taW5pbWFsKCkKeV9tYXggPC0gbWF4KHN1Ym1pc3Npb25fZGV0YWlsZWRfZGYkY29tbXVuaXR5TWF4LCBuYS5ybSA9IFRSVUUpCmhsaW5lcyA8LSBzZXEoMSwgeV9tYXgsIGJ5ID0gMSkKY19wbG90IDwtIGNfcGxvdCArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGhsaW5lcywgY29sb3IgPSAid2hpdGUiLCBsaW5ldHlwZSA9ICJzb2xpZCIpCgpwcmludCgoYl9wbG90IC8gZV9wbG90IC8gY19wbG90KSArCiAgcGxvdF9hbm5vdGF0aW9uKHRpdGxlID0gdXNlcmtleSkpCgpmb3IgKHAgaW4gb25hX3Bsb3RzKSB7CiAgcHJpbnQocCkKfQpgYGAKCgoK